#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <hw/inout.h>
#include <vcapture/capture.h>
#include <capture-imx8x-ext.h>

#include "capture_platform.h"
#include "capture_board.h"
#include "set_max2008x_power.h"

#define CAMERA_NAME_LEN_MAX 32
#define LIBNAME_LEN_MAX 128

#define CAPTURE_SOC_LIBNAME "libcapture-soc-imx8x.so"

#define	IMX_DEV_ISI 0
#define CAMERA_CNT_MAX 4

#define IMX8X_PIN_TYPE_UNKNOWN		0
#define IMX8X_PIN_TYPE_INTERNAL		1
#define IMX8X_PIN_TYPE_EXTERNAL		2
#define IMX8X_PIN_TYPE_NO_REQU		3  /*User does not want to reset the device*/

#define IMX8X_PIN_OP_LOW			0
#define IMX8X_PIN_OP_HIGH			1
#define IMX8X_PIN_OP_LOW_HIGH		2
#define IMX8X_PIN_OP_HIGH_LOW		3

static capture_log_context_t log_context;

struct _capture_context {
	capture_device_t soc;
	capture_device_t decoder_camera;
	int decoder_type;
	int vchannel;
	int camera_use;
	int src;
};

static int imx8_get_ctrl_type(const char *name, int *type);
static int imx8x_get_pin_info(const char *name, uint64_t *base_addr, uint32_t *offset);
static int imx8x_pin_operate(const char *name, int operate);
static int decoder_camera_reset(capture_context_t context, const char *name);
static int color_fix(void);

int capture_create_buffers(capture_context_t context, uint32_t property)
{
	capture_log_debug(log_context, 2, "(%s) context[0x%p] property[0x%08x]\n", __func__, context, property);
	return context->soc.api.capture_create_buffers(context->soc.ctx, property);
}

capture_context_t capture_create_context(uint32_t flags)
{
	capture_context_t context;

	capture_log_init();
	log_context = capture_log_create_context(CAPTURE_DEV_TYPE_BOARD, "imx8x");
	if (log_context < 0) {
		goto error_log;
	}
	capture_log_debug(log_context, 2, "(%s) flags[0x%08x]\n", __func__, flags);

	context = calloc(1, sizeof(struct _capture_context));
	if (!context) {
		capture_log_error(log_context, "calloc error\n");
		goto error_calloc;
	}

	/* load soc lib */
	if (capture_get_device_api(CAPTURE_SOC_LIBNAME, CAPTURE_DEV_TYPE_SOC, &context->soc.api) != 0) {
		capture_log_error(log_context, "soc capture_create_context is null\n");
		goto error_lib;
	}

	/* create so context */
	if (!(context->soc.ctx = context->soc.api.capture_create_context(flags))) {
		capture_log_error(log_context, "soc ctx create error\n");
		goto error_ctx;
	}

	/* set soc device property */
	if (context->soc.api.capture_set_property_i(context->soc.ctx, CAPTURE_PROPERTY_DEVICE, IMX_DEV_ISI) != 0) {
		capture_log_error(log_context, "soc capture_set_property_i error(%d:%s)\n", errno, strerror(errno));
		goto error_set_soc_device;
	}

	context->decoder_type = CAPTURE_DECODER_UNKNOWN;
	context->vchannel = -1;
	context->camera_use = CAPTURE_CAMERA_USE_0;
	context->src = 0;

	return context;

error_set_soc_device:
error_ctx:
error_lib:
	free(context);

error_calloc:
error_log:
	return NULL;
}

void capture_destroy_context(capture_context_t context)
{
	capture_log_debug(log_context, 2, "(%s) context[0x%p]\n", __func__, context);
	if (context->decoder_camera.api.capture_destroy_context) {
		context->decoder_camera.api.capture_destroy_context(context->decoder_camera.ctx);
	}
	context->soc.api.capture_destroy_context(context->soc.ctx);

	context->decoder_type = CAPTURE_DECODER_UNKNOWN;
	context->vchannel = -1;
	context->camera_use = CAPTURE_CAMERA_USE_0;
	context->src = 0;

	capture_log_destroy_context(log_context);
}

int capture_get_frame(capture_context_t context, uint64_t timeout, uint32_t flags)
{
	//capture_log_debug(log_context, 3, "(%s) context[0x%p] timeout[%lu] flags[0x%08x]\n", __func__, context, timeout, flags);
	return context->soc.api.capture_get_frame(context->soc.ctx, timeout, flags);
}

int capture_get_property_i(capture_context_t context, uint32_t prop, int32_t *value)
{
	//capture_log_debug(log_context, 2, "(%s) context[0x%p] prop[%s] value[0x%p]\n", __func__, context, capture_log_prop_str(prop), value);
	switch (prop) {
	case CAPTURE_PROPERTY_CAMERA_STATUS:
		return context->decoder_camera.api.capture_get_property_i(context->decoder_camera.ctx, prop, value);
	default:
		break;
	}

	return context->soc.api.capture_get_property_i(context->soc.ctx, prop, value);
}

int capture_get_property_p(capture_context_t context, uint32_t prop, void **value)
{
	capture_log_debug(log_context, 2, "(%s) context[0x%p] prop[%s] value[0x%p]\n", __func__, context, capture_log_prop_str(prop), value);
	return context->soc.api.capture_get_property_p(context->soc.ctx, prop, value);
}

int capture_is_property(capture_context_t context, uint32_t prop)
{
	capture_log_debug(log_context, 2, "(%s) context[0x%p] prop[%s]\n", __func__, context, capture_log_prop_str(prop));
	if ((prop == CAPTURE_PROPERTY_DECODER)
		|| (prop == CAPTURE_PROPERTY_CAMERA)
		|| (prop == CAPTURE_PROPERTY_CAMERA_USE)) {
		return 1;
	}

	if (context->soc.api.capture_is_property(context->soc.ctx, prop)) {
		return 1;
	}

	if (context->decoder_camera.api.capture_is_property) {
		if (context->decoder_camera.api.capture_is_property(context->decoder_camera.ctx, prop)) {
			return 1;
		}
	}
	else {
		capture_log_error(log_context, "decoder_camera decoder or camera not found, set CAPTURE_PROPERTY_DECODER and CAPTURE_PROPERTY_CAMERA first\n");
	}

	return 0;
}

int capture_put_buffer(capture_context_t context, uint32_t idx, uint32_t flags)
{
	capture_log_debug(log_context, 2, "(%s) context[0x%p] idx[%u] flags[0x%08x]\n", __func__, context, idx, flags);
	return context->soc.api.capture_put_buffer(context->soc.ctx, idx, flags);
}

int capture_release_frame(capture_context_t context, uint32_t idx)
{
	//capture_log_debug(log_context, 3, "(%s) context[0x%p] idx[%u]\n", __func__, context, idx);
	return context->soc.api.capture_release_frame(context->soc.ctx, idx);
}

int capture_set_property_i(capture_context_t context, uint32_t prop, int32_t value)
{
	static char *decoder_name = NULL;
	static char camera_name[CAMERA_NAME_LEN_MAX] = {0};
	static int camera_type = CAPTURE_CAMERA_TYPE_UNKNOWN;

	capture_log_debug(log_context, 2, "(%s) context[0x%p] prop[%s] value[%d(0x%08x)]\n", __func__, context, capture_log_prop_str(prop), value, value);

	switch (prop) {
	case CAPTURE_PROPERTY_DECODER:
	case CAPTURE_PROPERTY_CAMERA:
	{
		char libname[LIBNAME_LEN_MAX] = {0};
		capture_device_t *dev = NULL;
		if (prop == CAPTURE_PROPERTY_DECODER) {
			switch (value) {
			case CAPTURE_DECODER_MAX9286:
				decoder_name = "max9286";
				break;
			case CAPTURE_DECODER_MAX96706:
				decoder_name = "max96706";
				break;
			case CAPTURE_DECODER_TP2855:
				decoder_name = "tp2855";
				break;
			default:
				capture_log_error(log_context, "unknown decoder\n");
				errno = -EINVAL;
				goto error;
			}
			context->decoder_type = value;
		}
		else {
			if ((value > CAPTURE_DCAMERA_MIN) && (value < CAPTURE_DCAMERA_MAX)) {
				sprintf(camera_name, "no%d", value - CAPTURE_DCAMERA_MIN);
				camera_type = CAPTURE_CAMERA_TYPE_DIGITAL;
			}
			else if ((value > CAPTURE_ACAMERA_MIN) && (value < CAPTURE_ACAMERA_MAX)) {
				sprintf(camera_name, "no%d", value - CAPTURE_ACAMERA_MIN);
				camera_type = CAPTURE_CAMERA_TYPE_ANALOG;
			}
			else {
				capture_log_error(log_context, "unknown camera\n");
				errno = -EINVAL;
				goto error;
			}
		}
		if (decoder_name && camera_name[0] != '\0') {
			if (camera_type == CAPTURE_CAMERA_TYPE_DIGITAL) {
				sprintf(libname, "libcapture-decoder-dcamera-%s-%s.so", decoder_name, camera_name);
			}
			else {
				sprintf(libname, "libcapture-decoder-acamera-%s-%s.so", decoder_name, camera_name);
			}
			decoder_name = NULL;
			memset(camera_name, 0x00, CAMERA_NAME_LEN_MAX);
			dev = &context->decoder_camera;
		}
		else {
			break;
		}
		/* load decoder lib */
		if (capture_get_device_api(libname, CAPTURE_DEV_TYPE_DECODER_CAMERA, &dev->api) != 0) {
			capture_log_error(log_context, "decoder_camera(%s) get api error\n", libname);
			goto error;
		}

		capture_log_debug(log_context, 2, "decoder_camera lib %s loaded\n", libname);

		/* create so context */
		if (!(context->decoder_camera.ctx = dev->api.capture_create_context(0))) {
			capture_log_error(log_context, "decoder_camera(%s) ctx create error\n", libname);
			goto error;
		}

		capture_log_debug(log_context, 2, "decoder_camera context created %p\n", context->decoder_camera.ctx);

		break;
	}
	case CAPTURE_PROPERTY_VERBOSITY:
		capture_log_set_verbose(log_context, value);
		if (context->soc.api.capture_set_property_i(context->soc.ctx, CAPTURE_PROPERTY_VERBOSITY, value) != 0) {
			capture_log_error(log_context, "soc CAPTURE_PROPERTY_VERBOSITY set %d error(%d:%s)\n", value, errno, strerror(errno));
			goto error;
		}
		break;
	case CAPTURE_PROPERTY_DEVICE:
		/* soc device is set when context has be created */
		break;
	case CAPTURE_PROPERTY_SRC_INDEX:
		if ((value < IMX_ISI_SRC_MIPI_CSI_0) || (value > IMX_ISI_SRC_CI_PI)) {
			capture_log_error(log_context, "CAPTURE_PROPERTY_SRC_INDEX set error, %d/(%d, %d, %d)\n", value, IMX_ISI_SRC_MIPI_CSI_0, IMX_ISI_SRC_MIPI_CSI_1, IMX_ISI_SRC_CI_PI);
			goto error;
		}
		if (context->soc.api.capture_set_property_i(context->soc.ctx, prop, value)) {
			capture_log_error(log_context, "soc CAPTURE_PROPERTY_SRC_INDEX set 0x%08x error\n", value);
			goto error;
		}
		if ((value == IMX_ISI_SRC_MIPI_CSI_0) || (value == IMX_ISI_SRC_MIPI_CSI_1)) {
			if (context->soc.api.capture_set_property_i(context->soc.ctx, CAPTURE_PROPERTY_INTERFACE_TYPE, CAPTURE_IF_MIPI_CSI2)) {
				capture_log_error(log_context, "soc CAPTURE_PROPERTY_INTERFACE_TYPE set %d error\n", CAPTURE_IF_MIPI_CSI2);
				goto error;
			}
			if (context->soc.api.capture_set_property_i(context->soc.ctx, CAPTURE_PROPERTY_CSI2_NUM_DATA_LANES, 4)) {
				capture_log_error(log_context, "soc CAPTURE_PROPERTY_CSI2_NUM_DATA_LANES set 4 error\n");
				goto error;
			}
			context->src = value;
		}
		else {
			if (context->soc.api.capture_set_property_i(context->soc.ctx, CAPTURE_PROPERTY_INTERFACE_TYPE, CAPTURE_IF_PARALLEL)) {
				capture_log_error(log_context, "soc CAPTURE_PROPERTY_INTERFACE_TYPE set %d error\n", CAPTURE_IF_PARALLEL);
				goto error;
			}
			if (context->soc.api.capture_set_property_i(context->soc.ctx, CAPTURE_PROPERTY_IMX8X_CIPI_UV_SWAP_EN, 1)) {
				capture_log_error(log_context, "soc CAPTURE_PROPERTY_IMX8X_CIPI_UV_SWAP_EN set 1 error\n");
				goto error;
			}
			if (context->soc.api.capture_set_property_i(context->soc.ctx, CAPTURE_PROPERTY_IMX8X_CIPI_GCLK_MODE_EN, 1)) {
				capture_log_error(log_context, "soc CAPTURE_PROPERTY_IMX8X_CIPI_GCLK_MODE_EN set 1 error\n");
				goto error;
			}
		}
		break;
	case CAPTURE_PROPERTY_DECODER_I2C_ADDR:
		if (context->decoder_camera.api.capture_is_property(context->decoder_camera.ctx, prop) == 1) {
			if (context->decoder_camera.api.capture_set_property_i(context->decoder_camera.ctx, prop, value)) {
				capture_log_error(log_context, "decoder_camera 0x%08x set 0x%08x error\n", prop, value);
				goto error;
			}
		}
		else {
			capture_log_error(log_context, "decoder_camera no property %x\n", prop);
			goto error;
		}
		break;
	case CAPTURE_PROPERTY_CAMERA_TYPE:
		if (context->decoder_camera.api.capture_set_property_i(context->decoder_camera.ctx, prop, value)) {
			capture_log_error(log_context, "decoder_camera 0x%08x set 0x%08x error\n", prop, value);
			goto error;
		}
		break;
	case CAPTURE_PROPERTY_CSI2_VCHANNEL_NUM:
		if (context->soc.api.capture_set_property_i(context->soc.ctx, prop, value)) {
			capture_log_error(log_context, "soc set %s error\n", capture_log_prop_str(prop));
			goto error;
		}
		context->vchannel = value;
		break;
	case CAPTURE_PROPERTY_CAMERA_USE:
		if (context->decoder_camera.api.capture_is_property(context->decoder_camera.ctx, prop) == 1) {
			if (context->decoder_camera.api.capture_set_property_i(context->decoder_camera.ctx, prop, value)) {
				capture_log_error(log_context, "decoder_camera 0x%08x set 0x%08x error\n", prop, value);
				goto error;
			}
		}
		else {
			capture_log_error(log_context, "decoder_camera no property %x\n", prop);
			goto error;
		}
		context->camera_use = value;
		break;
	default:
		if (context->soc.api.capture_set_property_i(context->soc.ctx, prop, value)) {
			capture_log_error(log_context, "soc set %s error\n", capture_log_prop_str(prop));
			goto error;
		}
		break;
	}

	return 0;

error:
	return -1;
}

int capture_set_property_p(capture_context_t context, uint32_t prop, void *value)
{
	capture_log_debug(log_context, 2, "(%s) context[0x%p] prop[%s] value[%s]\n", __func__, context, capture_log_prop_str(prop), (char *)value);

	switch (prop) {
	case CAPTURE_PROPERTY_DECODER_I2C_PATH:
		if (context->decoder_camera.api.capture_set_property_p(context->decoder_camera.ctx, prop, value)) {
			capture_log_error(log_context, "decoder_camera set %s error\n", capture_log_prop_str(prop));
			goto error;
		}
		break;
	default:
		if (context->soc.api.capture_set_property_p(context->soc.ctx, prop, value)) {
			capture_log_error(log_context, "soc set %s error\n", capture_log_prop_str(prop));
			goto error;
		}
		break;
	}

	return 0;

error:
	return -1;
}

static int imx8_get_ctrl_type(const char *name, int *type)
{
	char *value;
	char key[128] = {0x00};

	sprintf(key, "%s_TYPE", name);
	value = getenv(key);
	if (!value) {
		capture_log_error(log_context, "evnironment varible %s not found\n", key);
		goto error;
	}

	if (strcmp(value, "INTERNAL") == 0) {
		*type = IMX8X_PIN_TYPE_INTERNAL;
	}
	else if (strcmp(value, "EXTERNAL") == 0) {
		*type = IMX8X_PIN_TYPE_EXTERNAL;
	}
	else if (strcmp(value, "NONE") == 0) {
		*type = IMX8X_PIN_TYPE_NO_REQU;
	}
	else {
		capture_log_error(log_context, "unknown control type %s\n", value);
		*type = IMX8X_PIN_TYPE_UNKNOWN;
		goto error;
	}

	capture_log_debug(log_context, 2, "%s control type %s\n", name, value);

	return 0;

error:
	return -1;
}

static int imx8x_get_pin_info(const char *name, uint64_t *base_addr, uint32_t *offset)
{
	char *value;
	char key[128] = {0x00};

	sprintf(key, "%s_PAD", name);
	value = getenv(key);
	if (!value) {
		capture_log_error(log_context, "evnironment varible %s not found\n", key);
		goto error;
	}

	sscanf(value, "%lx,%d", base_addr, offset);
	capture_log_debug(log_context, 2, "%s pin info: base_addr 0x%08lX, offset %u\n", name, *base_addr, *offset);

	return 0;

error:
	return -1;
}

static int imx8x_pin_operate(const char *name, int operate)
{
	uint64_t base_addr;
	uint32_t offset;
	uintptr_t mbase;
	uint32_t val;

	if (imx8x_get_pin_info(name, &base_addr, &offset) != 0) {
		capture_log_error(log_context, "get pin %s info error\n", name);
		goto error;
	}

	if ((mbase = mmap_device_io(8, base_addr)) == (uintptr_t)MAP_FAILED) {
		capture_log_error(log_context, "mmap %lx error\n", base_addr);
		goto error;
	}
	// set gpio direct out
	val = in32(mbase + 4);
	val |= (1 << offset);
	out32(mbase + 4, val);

	switch (operate) {
	case IMX8X_PIN_OP_LOW:
		// set gpio low
		val = in32(mbase);
		val &= ~(1 << offset);
		out32(mbase, val);
		break;
	case IMX8X_PIN_OP_HIGH:
		// set gpio high
		val = in32(mbase);
		val |= (1 << offset);
		out32(mbase, val);
		break;
	case IMX8X_PIN_OP_LOW_HIGH:
		// set gpio low
		val = in32(mbase);
		val &= ~(1 << offset);
		out32(mbase, val);
		delay(20);

		// set gpio high
		val = in32(mbase);
		val |= (1 << offset);
		out32(mbase, val);
		delay(20);
		break;
	case IMX8X_PIN_OP_HIGH_LOW:
		// set gpio high
		val = in32(mbase);
		val |= (1 << offset);
		out32(mbase, val);

		delay(10);

		// set gpio low
		val = in32(mbase);
		val &= ~(1 << offset);
		out32(mbase, val);
		break;
	}

	munmap_device_io(mbase, 8);

	return 0;

error:
	return -1;
}

static int decoder_camera_reset(capture_context_t context, const char *name)
{
	int type;

	if (imx8_get_ctrl_type(name, &type) != 0) {
		capture_log_debug(log_context, 2, "%s control type %d\n", name, type);
		goto error;
	}

	switch (type) {
	case IMX8X_PIN_TYPE_NO_REQU:
		capture_log_debug(log_context, 2, "%s user configure device reset pin to none.\n", name);
		break;
	case IMX8X_PIN_TYPE_INTERNAL:
		imx8x_pin_operate(name, IMX8X_PIN_OP_LOW_HIGH);
		break;
	case IMX8X_PIN_TYPE_EXTERNAL:
		switch (context->decoder_type) {
			case CAPTURE_DECODER_MAX9286:
				if (strcmp(name, "MAX9286_CAM") == 0) {
					max9286_power(0x0F, 0);
					delay(20);
					max9286_power(0x0F, 1);
				}
				break;
			case CAPTURE_DECODER_MAX96706:
				if (strcmp(name, "MAX96706_CAM") == 0) {
					max96706_power(0x01, 0);
					delay(20);
					max96706_power(0x01, 1);
				}
				break;
			case CAPTURE_DECODER_TP2855:
				if (strcmp(name, "TP2855_CAM") == 0) {
					/* nop */
				}
				break;
			default:
				break;
		}
		break;
	default:
		capture_log_error(log_context, "unknown control type %d\n", type);
		goto error;
	}

	return 0;

error:
	return -1;
}

static int color_fix(void)
{
	uintptr_t mbase;
	uint64_t base_addr = 0x58261000; /* csr base */
	if ((mbase = mmap_device_io(64, base_addr)) == (uintptr_t)MAP_FAILED) {
		capture_log_error(log_context, "mmap %lx error\n", base_addr);
		goto error;
	}

	out32(mbase + 0x18, 0x2800000);

	munmap_device_io(mbase, 64);

	return 0;

error:
	return -1;
}

static int reset_dphy(capture_context_t context)
{
	uintptr_t mbase;
	uint64_t base_addr;
	if (context->src == IMX_ISI_SRC_MIPI_CSI_0) {
		base_addr = 0x58227104;
	}
	else {
		base_addr = 0x58247104;
	}

	if ((mbase = mmap_device_io(4, base_addr)) == (uintptr_t)MAP_FAILED) {
		capture_log_error(log_context, "mmap %lx error\n", base_addr);
		goto error;
	}

	out32(mbase, 0x0000000F);

	munmap_device_io(mbase, 4);

	return 0;

error:
	return -1;
}

int capture_update(capture_context_t context, uint32_t flags)
{
	capture_log_debug(log_context, 2, "(%s) context[0x%p] flags[0x%08x]\n", __func__, context, flags);

	/* power control of decoder and cameras must before soc context update, you must update vchannel 0 first */
	if (context->vchannel == 0) {
		if (((context->src == IMX_ISI_SRC_MIPI_CSI_0) || (context->src == IMX_ISI_SRC_MIPI_CSI_1)) && reset_dphy(context) != 0) {
			capture_log_error(log_context, "imx8x reset d-phy error\n");
			goto error;
		}

		switch (context->decoder_type) {
		case CAPTURE_DECODER_MAX9286:
			if (decoder_camera_reset(context, "MAX9286_PDB") != 0) {
				capture_log_error(log_context, "decoder_camera MAX9286_PDB control error\n");
				goto error;
			}

			/* camera power IC 20086 and 96076 in the same i2c bus, if it do not init rightly, the bus will be problematic */
			if (decoder_camera_reset(context, "MAX96706_PDB") != 0) {
				capture_log_error(log_context, "decoder_camera MAX96706_PDB control(for 20086 IC) error\n");
				goto error;
			}

			delay(20);

			if (decoder_camera_reset(context, "MAX9286_CAM") != 0) {
				capture_log_error(log_context, "decoder_camera MAX9286_CAM control error\n");
				goto error;
			}

			break;
		case CAPTURE_DECODER_MAX96706:
			if (decoder_camera_reset(context, "MAX96706_PDB") != 0) {
				capture_log_error(log_context, "decoder_camera MAX96706_PDB control error\n");
				goto error;
			}

			delay(20);

			if (decoder_camera_reset(context, "MAX96706_CAM") != 0) {
				capture_log_error(log_context, "decoder_camera MAX96706_CAM control error\n");
				goto error;
			}
			delay(400);

			break;
		case CAPTURE_DECODER_TP2855:
			if (decoder_camera_reset(context, "TP2855_PDB") != 0) {
				capture_log_error(log_context, "decoder_camera TP2855_PDB control error\n");
				goto error;
			}

			delay(20);

			if (decoder_camera_reset(context, "TP2855_CAM") != 0) {
				capture_log_error(log_context, "decoder_camera TP2855_CAM control error\n");
				goto error;
			}

			delay(20);

			break;
		default:
			capture_log_error(log_context, "decoder_camera decoder or camera not found, set CAPTURE_PROPERTY_DECODER and CAPTURE_PROPERTY_CAMERA first(1)\n");
			goto error;
		}

		/* init decoder and camera */
		if (context->decoder_camera.api.capture_update) {
			if (context->decoder_camera.api.capture_update(context->decoder_camera.ctx, flags) != 0) {
				capture_log_error(log_context, "decoder_camera capture_update error\n");
				goto error;
			}
		}
		else {
			capture_log_error(log_context, "decoder_camera decoder or camera not found, set CAPTURE_PROPERTY_DECODER and CAPTURE_PROPERTY_CAMERA first(2)\n");
			goto error;
		}

		/* disable decoder output */
		if (context->decoder_camera.api.capture_is_property(context->decoder_camera.ctx, CAPTURE_PROPERTY_DECODER_ENABLE) == 1) {
			if (context->decoder_camera.api.capture_set_property_i(context->decoder_camera.ctx, CAPTURE_PROPERTY_DECODER_ENABLE, CAPTURE_DECODER_DISABLE)) {
				capture_log_error(log_context, "decoder_camera CAPTURE_PROPERTY_DECODER_ENABLE set CAPTURE_DECODER_DISABLE error\n");
				goto error;
			}
		}
		else {
			capture_log_error(log_context, "decoder_camera no property CAPTURE_PROPERTY_DECODER_ENABLE\n");
			goto error;
		}
	}

	if (context->soc.api.capture_update(context->soc.ctx, flags) != 0) {
		capture_log_error(log_context, "soc capture_update error %d(%s)\n", errno, strerror(errno));
		goto error;
	}

	delay(50);

	if (context->vchannel + 1 == context->camera_use) {
		/* enable decoder output */
		if (context->decoder_camera.api.capture_is_property(context->decoder_camera.ctx, CAPTURE_PROPERTY_DECODER_ENABLE) == 1) {
			if (context->decoder_camera.api.capture_set_property_i(context->decoder_camera.ctx, CAPTURE_PROPERTY_DECODER_ENABLE, CAPTURE_DECODER_ENABLE)) {
				capture_log_error(log_context, "decoder_camera CAPTURE_PROPERTY_DECODER_ENABLE set CAPTURE_DECODER_ENABLE error\n");
				goto error;
			}
		}
		else {
			capture_log_error(log_context, "decoder_camera no property CAPTURE_PROPERTY_DECODER_ENABLE\n");
			goto error;
		}
		/* operate for particular decoder */
		switch (context->decoder_type) {
		case CAPTURE_DECODER_MAX9286:
			delay(100); /* avoid dark to light */
			break;
		case CAPTURE_DECODER_MAX96706:
			if (decoder_camera_reset(context, "MAX96706_GPI") != 0) {
				capture_log_error(log_context, "decoder_camera MAX9286_GPI control error\n");
				goto error;
			}
			if (color_fix() != 0) {
				capture_log_error(log_context, "decoder_camera max96706 coder fix error\n");
				goto error;
			}
			delay(600); /* avoid green frame */
			break;
		case CAPTURE_DECODER_TP2855:
			delay(300); /* avoid green frame, 250ms NG */
			break;
		default:
			capture_log_error(log_context, "decoder_camera decoder or camera not found, set CAPTURE_PROPERTY_DECODER and CAPTURE_PROPERTY_CAMERA first(3)\n");
			goto error;
		}
	}

	return 0;

error:
	return -1;
}

int capture_get_reg(capture_context_t context, uint32_t page, uint32_t reg, uint32_t* data)
{
	//capture_log_debug(log_context, 2, "(%s) context[0x%p] page[%d] reg[0x%02x]\n", __func__, context, page, reg);
	context->decoder_camera.api.capture_get_reg(context->decoder_camera.ctx, page, reg, data);
	return 0;
}
